package com.itheima.wallet.user.service;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.wallet.user.api.UserLoginServiceApi;
import com.itheima.wallet.user.mapper.UserMapper;
import com.itheima.wallet.user.pojos.User;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Service;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service(version = "1.0.0")
public class UserLoginService implements UserLoginServiceApi {
    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Value("${jwt.secret}")
    private String secret;


    /**
     * 用户登录的方法
     * @param phone 手机号
     * @param code
     * @return
     */
    @Override
    public String login(String phone,String code) {
        try {
            //判断参数
            if(StringUtils.isEmpty(phone)||StringUtils.isEmpty(code)){
                return null;
            }

            //先去redis中核对验证码
            String redisKey  = "CHECK_CODE_"+phone;


            //获取redis中的验证码
            String redisValue = this.redisTemplate.opsForValue().get(redisKey);

            //核对验证码
            if(StringUtils.isEmpty(redisValue)||!StringUtils.equals(code,redisValue)){
                //验证码和redis中的不相同则登录失败
                return null;
            }
            //如果验证码通过则把redis中的数据删除
            //redisTemplate.delete(redisKey);

            //之后调用mapper查询数据库，看是不是新用户
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            //根据手机号查询
            wrapper.eq("phone",phone);
            User user = (User) this.userMapper.selectOne(wrapper);
            //判断
            if(user==null){
                //如果查询结果为空表示为新用户，就返回null,到controller层
                // 给予提示，要用户先注册
               return null;
            }
            //如果不是新用户则生成token
            //将数据表中的id生成token
            Map<String,Object> claims = new HashMap<String,Object>();
            claims.put("id",user.getId());
            //claims.put("id",1);

            //生成token
            String jwt = Jwts.builder()
                    .setClaims(claims)
                    .signWith(SignatureAlgorithm.HS256, secret)
                    .setExpiration(new DateTime().plusHours(12).toDate())
                    .compact();
            return jwt;
        } catch (Exception e) {
            e.printStackTrace();
        }
        //如果出错
        return null;
    }

    /**
     *  进行token的校验
     * @param token  传过来的token
     * @return 通过token查询到的用户信息
     */
    public User checkTokenService(String token) {
        try{
            //解析传过来的token
            Map<String,Object> body = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();

            //然后将token中的id取出
            Object idObject = body.get("id");
            //转换成String类型
            String idStr = idObject.toString();
            //转换成long类型
            Long id = Long.valueOf(idStr);

            //创建user对象，把id封装到user对象
            User user = new User();
            user.setId(id);

            /*
            说明：因为需要返回user对象中的mobile，需要查询数据库获取到mobile数据
            如果每次都查询数据库，必然会导致性能问题，需要对用户的手机号进
             行缓存操作
            数据缓存时，需要设置过期时间，过期时间要与token的时间一致
            如果用户修改了手机号，需要同步修改redis中的数据
            */

            //查询redis中有没有该用户的手机号
            //定义redis的key
            String redisKey = "TANHUA_USER_MOBILE_" + user.getId();
            if(this.redisTemplate.hasKey(redisKey)){
                //如果有，则取出并封装到user对象中
                String mobile = this.redisTemplate.opsForValue().get(redisKey);
                user.setPhone(mobile);
                return user;
            }else{
                //如果没有，则去数据库中查
                User u = this.userMapper.selectById(user.getId());
                //将查出来的手机号封装到user中
                user.setPhone(u.getPhone());
                //并把手机号存入到redis中，设置的有效期跟token的
                //有效期一致
                Object exp = body.get("exp");
                String s = exp.toString();
                Long time = Long.valueOf(s)*1000;//此单位为秒，所以乘以千换成毫秒
                //用设置的时间前去当前的时间，就是还剩下的有效时间
                long timeout = time - System.currentTimeMillis();
                //将手机号设置到redis中
                this.redisTemplate.opsForValue().set(redisKey,u.getPhone(),timeout, TimeUnit.MILLISECONDS);
                return user;
            }

            //System.out.println(body);
        }catch(ExpiredJwtException e){
            System.out.println("token已经过期了");
            //Log.info("token已经过期",token);
        }catch(Exception e){
            System.out.println("无效的token");
            //Log.error("无效的token，token=",token,e);
        }


        return null;
    }
}
